﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using FileTransportSpace;
using System.IO;
using System.Diagnostics;
using System.Threading;
using VCommons;
namespace Thrift.Server
{
    /// <summary>
    /// 文件传输服务实现（handle）
    /// </summary>
    public class FileTransportHandler : FileTransport.Iface
    {
        /// <summary>
        /// 内存数据库，使用IList实现集合，更安全，List类型发放的操作太多了，呵呵。
        /// </summary>
        public readonly static IList<DataSync> DbMemory = new List<DataSync>();
        /// <summary>
        /// 日志跟踪文件
        /// </summary>
        string LogDbName = "\\fileUploadLog.xml";

        List<DataSync> DataSyncArr = new List<DataSync>();
        #region Private Methods
        /// <summary>
        /// 檢測和生成目錄
        /// </summary>
        /// <param name="fileUrl"></param>
        private void Chk_GeneratorDir(string fileUrl)
        {
            if (string.IsNullOrWhiteSpace(fileUrl))
                throw new ArgumentNullException("存储路不能为空.");

            string folder = Path.GetDirectoryName(fileUrl);
            if (!Directory.Exists(folder))
                Directory.CreateDirectory(folder);
        }
        #endregion

        #region Iface Member
        /// <summary>
        /// 从服务器下载文件流
        /// </summary>
        /// <param name="fileUrl"></param>
        /// <returns></returns>
        public DataSegment Download(DataSegment dataSegment)
        {
            Chk_GeneratorDir(dataSegment.Filename);
            LogDbName = "\\fileDownLog.xml";

            using (FileStream fs = new FileStream(dataSegment.Filename, FileMode.Open, FileAccess.Read))
            {
                int readBytes = 0;
                byte[] buffer = new byte[1024 * 1024 * 4];//开避4M的缓冲区0x1000为4K
                fs.Position = dataSegment.CurrentSeek;//默认值，如果是断点续传，需要存储当前position的位置

                if ((readBytes = fs.Read(buffer, 0, buffer.Length)) <= 0)
                    return null;

                //发送1次
                UpdateDataSync(new DataSync
                {
                    FilePath = dataSegment.Filename,
                    IsSync = true,
                    CurrentSeek = fs.Position,
                    ClientKey = dataSegment.ClientKey,
                });

                return new DataSegment { CurrentBytes = readBytes, Data = buffer };

            }
        }

        /// <summary>
        /// 上传数据包
        /// </summary>
        /// <param name="dataSegment"></param>
        /// <param name="desPath"></param>
        /// <returns></returns>
        public bool Upload(DataSegment dataSegment)
        {
            Chk_GeneratorDir(dataSegment.Filename);

            using (FileStream stream = new FileStream(dataSegment.Filename, FileMode.Append, FileAccess.Write))
            {
                stream.Write(dataSegment.Data, 0, dataSegment.CurrentBytes);
            }

            //更新desPath的写入状态，一般来说，一次传递4M数据
            var log = new DataSync
            {
                FilePath = dataSegment.Filename,
                IsSync = true,
                CurrentSeek = dataSegment.CurrentSeek,
                ClientKey = dataSegment.ClientKey,
                OrderNumber = dataSegment.OrderNumber,
                OccurTime = DateTime.Now.ToString(),
            };

            UpdateDataSync(log);//总进度
            DataSyncArr.Add(log);//文件列表

            System.Console.ForegroundColor = ConsoleColor.Green;
            System.Console.WriteLine("向文件{0}写入数据{1}/{2}", dataSegment.Filename, dataSegment.CurrentBytes, dataSegment.FileSize);
            return true;//返回给客户端
        }

        /// <summary>
        /// 是否要进行同步
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public DataSync IsSync(string fileName, string clientKey)
        {
            if (string.IsNullOrWhiteSpace(fileName))
                throw new ArgumentNullException("存储路不能为空.");

            DataSync dataSync = new DataSync
            {
                CurrentSeek = 0,
                IsSync = true,
                FilePath = fileName,
                ClientKey = clientKey,
            };

            string folder = Path.GetDirectoryName(fileName);
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
                return dataSync;
            }

            List<DataSync> db = (List<DataSync>)SerializationHelper.DeserializeFromBinary(folder + LogDbName);
            if (db != null && db.Any())
            {
                return db.FirstOrDefault(i => i.FilePath == fileName
                    && i.ClientKey == clientKey)
                    ?? dataSync;
            }
            return dataSync;
        }

        /// <summary>
        /// 更新数据同步记录的状态
        /// </summary>
        /// <param name="dataSync"></param>
        /// <returns></returns>
        public bool UpdateDataSync(DataSync dataSync)
        {

            if (!dataSync.IsSync)//客户端告诉服务器已经上传成功，这时，服务器插入日志列表
                InsertLogFile(DataSyncArr, dataSync.FilePath);

            string dbName = Path.GetDirectoryName(dataSync.FilePath) + LogDbName;
            List<DataSync> db = (List<DataSync>)SerializationHelper.DeserializeFromBinary(dbName) ?? new List<DataSync>();
            var entity = db.FirstOrDefault(i => i.FilePath == dataSync.FilePath && i.ClientKey == dataSync.ClientKey);

            if (entity != null)//更新上传进度
            {
                entity.IsSync = dataSync.IsSync;
                entity.CurrentSeek = dataSync.CurrentSeek;
            }
            else//第一次上传
            {
                db.Add(new DataSync
                {
                    CurrentSeek = 0,
                    FilePath = dataSync.FilePath,
                    IsSync = true,
                    ClientKey = dataSync.ClientKey,
                    OccurTime = DateTime.Now.ToString(),
                });
            }
            db.ForEach(i => Console.WriteLine(i.ToString()));

            SerializationHelper.SerializableToBinary(dbName, db);

            return dataSync.IsSync;
        }

        /// <summary>
        /// 得到文件大小
        /// </summary>
        /// <param name="dataSync"></param>
        /// <returns></returns>
        public long GetFileSize(DataSync dataSync)
        {
            return new FileInfo(dataSync.FilePath).Length;
        }

        #endregion

        /// <summary>
        /// 插入日志文件
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="data"></param>
        void InsertLogFile(List<DataSync> dataSegment, string filePath)
        {
            string dbName = Path.GetDirectoryName(filePath) + " \\" + LogDbName + "_log.xml";
            SerializationHelper.SerializeToXml(dbName, DataSyncArr.ToArray());
        }
    }
}
